/*use std::collections::HashMap;

struct TreeNode<D> {
    children: HashMap<String, Box<TreeNode<D>>>,
    data: Option<D>
}

impl<D> TreeNode<D> {
    fn new() -> Self { Self { children: HashMap::new(), data: None } }
    fn inject_path<S: Into<String>>(&mut self, path: Vec<S>, data: D) {
        let tail = path.into_iter().fold(
            self,
            |node, seg| {
                let e = node.children
                    .entry(seg.into())
                    .or_insert_with(|| Box::new(TreeNode::new()));
                e.as_mut()
            }
        );
        tail.data = Some(data);
    }
}

pub struct PathResolver<D> {
    root: TreeNode<D>,
}


pub struct ResolverResult<'a, 's, 'w, D> {
    pub matched: &'a[&'w str],
    pub remainder: &'a[&'w str],
    pub data: Option<&'s D>
}


impl<D> PathResolver<D> {
    pub fn new<S: Into<String>>(source: impl Iterator<Item = (Vec<S>, D)>) -> Self {
        let root = source.fold(
            TreeNode::new(), 
            |mut m, (v, d)| { m.inject_path(v, d); m }
        );
        Self { root }
    }

    pub fn resolve<'a, 's, 'w>(&'s self, path: &'a Vec<&'w str>) -> ResolverResult<'a, 's, 'w, D> {

        let result = path.iter().enumerate().try_fold(
            (&self.root, self.root.data.as_ref().map(|d| (0, d))), 
            |(n, closest_dpoint), (pos, &seg)| {              
                match n.children.get(seg) {
                    Some(n) => Ok((n as &TreeNode<D>, n.data.as_ref().map(|d| (pos + 1, d)).or(closest_dpoint))),
                    None => Err(closest_dpoint)
                }
            }
        );

        let closest_dpoint = match result {
            Ok((_, p)) => p,
            Err(p) => p
        };
        let remainder_offset = closest_dpoint.map(|(p, _)|p).unwrap_or(0);
        let matched = &path[0..remainder_offset];
        let remainder = &path[remainder_offset..];
        let data = closest_dpoint.map(|(_, d)| d);
        ResolverResult { matched, remainder, data }
    }
}

#[test]
fn test_path_resolver() {
    let res = PathResolver::new(
        [
            (vec![], "/index.html"),
            (vec!["a", "b", "c"], "a/b/c"),
            (vec!["a", "b", "z"], "a/b/z"),
        ].into_iter()
    );

    macro_rules! tr {
        ($in:tt, $data:expr, -, $rmdr:expr) => {
            let src = vec! $in;
            let ResolverResult { remainder, data, .. } = res.resolve(&src);
            assert_eq!(data, $data);
            assert_eq!(remainder, $rmdr as &[&str]);            
        };
        ($in:tt, $data:expr, $matched:expr, $rmdr:expr) => {
            let src = vec! $in;
            let ResolverResult { remainder, data, matched } = res.resolve(&src);
            assert_eq!(data, $data);
            assert_eq!(matched, $matched as &[&str]);            
            assert_eq!(remainder, $rmdr as &[&str]);            
        };
    }

    tr!([], Some(&"/index.html"), &[], &[]);
    tr!(["a", "b", "c"],  Some(&"a/b/c"), -, &[]);
    tr!(["a", "b", "c", "z"],  Some(&"a/b/c"), &["a", "b", "c"], &["z"]);
    tr!(["a", "b", "c", "z", "y"],  Some(&"a/b/c"), -, &["z", "y"]);
    tr!(["a"],  Some(&"/index.html"), -, &["a"]);
    tr!(["a", "y", "x"],  Some(&"/index.html"), &[], &["a", "y", "x"]);
    tr!(["a", "b", "z"],  Some(&"a/b/z"), -, &[]);
    tr!(["a", "b", "z", "z"],  Some(&"a/b/z"), -, &["z"]);
}
*/